﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MainWindow.xaml.cs" company="">
//   
// </copyright>
// <summary>
//   Interaction logic for MainWindow.xaml
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DarkBone.Player
{
   using System;
   using System.Collections.Generic;
   using System.Diagnostics;
   using System.Globalization;
   using System.Linq;
   using System.Speech.Synthesis;
   using System.Threading;
   using System.Windows;
   using System.Windows.Media;
   using System.Windows.Media.Imaging;
   using System.Windows.Threading;


   using DarkBone.Engine;
   using DarkBone.Engine.EventArgs;
   using DarkBone.Engine.Networking;

   /// <summary>
   /// Interaction logic for MainWindow.xaml
   /// </summary>
   public partial class MainWindow : Window
   {
      /// <summary>
      /// Collector client
      /// </summary>
      private Collector collector;

      /// <summary>
      /// Map background
      /// </summary>
      private ImageSource background;

      /// <summary>
      /// Thread Speaker
      /// </summary>
      private Thread speaker;

      /// <summary>
      /// thread stopper
      /// </summary>
      private bool running = true;

      private object locker = new object();
      
      private Queue<string> messages;
      
      #region Constructors and Destructors

      /// <summary>
      /// Initializes a new instance of the <see cref="MainWindow"/> class.
      /// </summary>
      public MainWindow()
      {
         Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
         if (Debug.Listeners.Count > 0)
         {
            //DebugConsole.AllocConsole();
         }
         this.messages = new Queue<string>();
         this.speaker = new Thread(new ParameterizedThreadStart(this.Speaker));
         this.speaker.Start();

         this.InitializeComponent();
      }

      private void Speaker(object obj)
      {
			 var synth = new SpeechSynthesizer();     
          while (this.running)
          {
             Thread.Sleep(10);
             var msg = string.Empty;
             //lock (this.locker)
             //{
             //  if (this.messages.Count > 0)
             //  {
             //     msg = this.messages.Dequeue();
             //  }
             //}
             //if (!string.IsNullOrEmpty(msg))
             //{
             //      synth.Speak(msg);
             //}
          }
          synth.Dispose();  
      }

      /// <summary>
      /// Finalizes an instance of the <see cref="MainWindow"/> class. 
      /// Releases unmanaged resources and performs other cleanup operations before the
      /// <see cref="MainWindow"/> is reclaimed by garbage collection.
      /// </summary>
      ~MainWindow()
      {
         this.running = false;
         if (this.collector != null)
         {
            this.collector.Stop();
         }
      }

      #endregion

      /// <summary>
      /// Deletes the object.
      /// </summary>
      /// <param name="handleObject">The handle object.</param>
      /// <returns>
      /// Whatever true
      /// </returns>
      [System.Runtime.InteropServices.DllImport("gdi32.dll")]
      public static extern bool DeleteObject(IntPtr handleObject);

      #region Methods

      /// <summary>
      /// The window_ loaded.
      /// </summary>
      /// <param name="sender">
      /// The sender.
      /// </param>
      /// <param name="e">
      /// The e.
      /// </param>
      private void Window_Loaded(object sender, RoutedEventArgs e)
      {
         this.collector = new Collector(Role.Client, "SC2");
         this.collector.OnGameStart += new Collector.GameStartEventHandler(this.OnGameStart);
         this.collector.OnGameEnd += new Collector.GameEndEventHandler(this.OnGameEnd);
         this.collector.OnGameTimerChanged += new Collector.GameTimerChangedEventHandler(this.OnGameTimerChanged);
         this.collector.OnCollectTick += new Collector.CollectTickEventHandler(this.OnCollectTick);
         this.collector.OnUnitCreated += new Collector.UnitCreatedEventHandler(this.OnUnitCreated);
         this.collector.OnUnitModified += new Collector.UnitModifiedEventHandler(this.OnUnitModified);
         this.collector.OnUnitDestroyed += new Collector.UnitDestroyedEventHandler(this.OnUnitDestroyed);
         this.collector.Start();

         // var networking = new Networking(Networking.NetworkingRole.Client, null);
         
         // object o = networking.Query(task);
      }

      /// <summary>
      /// Handles the Closed event of the Window control.
      /// </summary>
      /// <param name="sender">The source of the event.</param>
      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
      private void Window_Closed(object sender, EventArgs e)
      {
         if (this.collector != null)
         {
            this.collector.Stop();
         }
      }

      private void OnMessage(string message)
      {
         this.Dispatcher.Invoke(
            DispatcherPriority.Normal,
            (Action)delegate 
            {
                  textBox1.Text += message + Environment.NewLine;
                  textBox1.ScrollToEnd();
            }
         );
         lock (this.locker)
         {
             messages.Enqueue(message);
         }
      }

      /// <summary>
      /// Called when [game start].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
      private void OnGameStart(object sender, EventArgsGame e)
      {
         this.OnMessage("Game started: " + e.SecsElapsed);
         this.Dispatcher.Invoke(
            DispatcherPriority.Normal,
            (Action)delegate
               {
                  var handleBitmap = IntPtr.Zero;
                  try
                  {
                     handleBitmap = ((System.Drawing.Bitmap)e.MapInfo.Template.Background).GetHbitmap();
                     this.background = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                        handleBitmap,
                        IntPtr.Zero,
                        System.Windows.Int32Rect.Empty,
                        BitmapSizeOptions.FromWidthAndHeight(1000, 1000));
                  } 
                  finally
                  {
                     DeleteObject(handleBitmap);
                  }
               });
      }

      /// <summary>
      /// Called when [game end].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
      private void OnGameEnd(object sender, EventArgsGame e)
      {
         this.OnMessage("Game ended: " + e.SecsElapsed);
      }

      /// <summary>
      /// Called when [game timer changed].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The e.</param>
      private void OnGameTimerChanged(object sender, EventArgsGameTime e)
      {
         //this.OnMessage("Gametime " + e.SecsElapsed + ".");
      }

      /// <summary>
      /// Called when [game timer changed].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The e.</param>
      private void OnCollectTick(object sender, EventArgsCollectTick e)
      {
         //this.OnMessage("Ticked " + e.SecsElapsed + ".");
         this.Dispatcher.Invoke(
            DispatcherPriority.Normal,
            (Action)delegate
               {
                     DrawingGroup dGroup = new DrawingGroup();
                     var shapeOutlinePen = new Pen(Brushes.Black, 2);
                     shapeOutlinePen.Freeze();
                     using (var dc = dGroup.Open())
                     {
                        dc.DrawImage(this.background, new Rect(0, 0, 1000, 1000));
                        dc.PushOpacity(0.5);
                        dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, 1000, 1000));
                        dc.Pop();
                        foreach (var player in e.Players)
                        {
                           var brush = new SolidColorBrush(e.TeamColorEnabled ? Color.FromRgb(player.TeamColor.R, player.TeamColor.G, player.TeamColor.B) : Color.FromRgb(player.Color.R, player.Color.G, player.Color.B));
                           foreach (var unit in player.Units.Where(unit => unit.Template.VisibleStatus))
                           {
                              dc.DrawRectangle(brush, shapeOutlinePen, new Rect(unit.X - ((unit.Template.Size.Width + 4) / 2), unit.Y - ((unit.Template.Size.Height + 4) / 2), unit.Template.Size.Width + 4, unit.Template.Size.Height + 4));
                              if (unit.Template.Size.Width <= 15)
                              {
                                 continue;
                              }

                              var handleBitmap = IntPtr.Zero;
                              try
                              {
                                 handleBitmap = ((System.Drawing.Bitmap)unit.Template.Image).GetHbitmap();
                                 var unitImage = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                                    handleBitmap,
                                    IntPtr.Zero,
                                    System.Windows.Int32Rect.Empty,
                                    BitmapSizeOptions.FromWidthAndHeight(unit.Template.Image.Width, unit.Template.Image.Height));
                                 dc.DrawImage(unitImage, new Rect(unit.X - ((unit.Template.Size.Width) / 2) + 2, unit.Y - ((unit.Template.Size.Height) / 2) + 2, unit.Template.Size.Width - 4, unit.Template.Size.Height - 4));
                              } 
                              finally
                              {
                                 DeleteObject(handleBitmap);
                              }
                           }
                        }
                        image1.Source = new DrawingImage(dGroup);;
                     }
                     dGroup = new DrawingGroup();
                     using (var dc = dGroup.Open())
                     {
                        var wx = 150;
                        var wy = 600;
                        dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, wx, wy));
                        var iterPlayer = 0;
                        foreach (var player in e.Players)
                        {
                           if (!player.Enemy)
                           {
                              continue;
                           }

                           var brush = new SolidColorBrush(e.TeamColorEnabled ? Color.FromRgb(player.TeamColor.R, player.TeamColor.G, player.TeamColor.B) : Color.FromRgb(player.Color.R, player.Color.G, player.Color.B));
                           var iterUnitBuilding = 0;
                           var iterUnitUnit = 0;
                           foreach (var summary in player.UnitSummary)
                           {
                              if ((summary.Template.Image == null) || (summary.ModelNumber == 0))
                              {
                                 continue;
                              }

                              var handleBitmap = IntPtr.Zero;
                              try
                              {
                                 handleBitmap = ((System.Drawing.Bitmap)summary.Template.Image).GetHbitmap();
                                 var unitImage = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                                    handleBitmap,
                                    IntPtr.Zero,
                                    System.Windows.Int32Rect.Empty,
                                    BitmapSizeOptions.FromWidthAndHeight(summary.Template.Image.Width, summary.Template.Image.Height));
                                 if (summary.Template.Building)
                                 {
                                    //dc.DrawRectangle(brush, null, new Rect(3 + 940 - (iterUnitBuilding * 50), 3 + iterPlayer * 50, 48, 48));
                                    //dc.DrawImage(unitImage, new Rect(5 + 940 - (iterUnitBuilding * 50), 5 + iterPlayer * 50, 45, 45));
                                    //dc.DrawText(new FormattedText(summary.Count.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 25, Brushes.LimeGreen), new Point(7 + 940 - (iterUnitBuilding * 50), 23 + iterPlayer * 50));
                                    dc.DrawRectangle(brush, null, new Rect(3 + (iterPlayer * 50), 3 + wy - (iterUnitBuilding * 50), 48, 48));
                                    dc.DrawImage(unitImage, new Rect(5 + (iterPlayer * 50), 5 +  wy - (iterUnitBuilding * 50), 45, 45));
                                    dc.DrawText(new FormattedText(summary.Count.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 25, Brushes.LimeGreen), new Point(7 + (iterPlayer * 50), 23 + wy - (iterUnitBuilding * 50)));
                                    ++iterUnitBuilding;
                                 }
                                 else
                                 {
                                    //dc.DrawRectangle(brush, null, new Rect(3 + iterUnitUnit * 50, 3 + iterPlayer * 50, 48, 48));
                                    //dc.DrawImage(unitImage, new Rect(5 + iterUnitUnit * 50, 5 + iterPlayer * 50, 45, 45));
                                    //dc.DrawText(new FormattedText(summary.Count.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 25, Brushes.LimeGreen), new Point(7 + iterUnitUnit * 50, 23 + iterPlayer * 50));
                                    dc.DrawRectangle(brush, null, new Rect(3 + iterPlayer * 50, 3 + iterUnitUnit * 50, 48, 48));
                                    dc.DrawImage(unitImage, new Rect(5 + iterPlayer * 50, 5 + iterUnitUnit * 50, 45, 45));
                                    dc.DrawText(new FormattedText(summary.Count.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Verdana"), 25, Brushes.LimeGreen), new Point(7 + iterPlayer * 50, 23 + iterUnitUnit * 50));
                                    ++iterUnitUnit;
                                 }
                              } 
                              finally
                              {
                                 DeleteObject(handleBitmap);
                              }
                           }
                           ++iterPlayer;
                        }
                     }
                     image2.Source = new DrawingImage(dGroup);
                     dGroup = new DrawingGroup();
                     using (var dc = dGroup.Open())
                     {
                        foreach (var player in e.Players)
                        {
                           var pathGeometry = new PathGeometry();
                           if ((!player.Enemy) || (player.ArmySize.Count <= 1) || (player.PlayerStruct.Teamslot == 0x10))
                           {
                              continue;
                           }
                           var pathFigure = new PathFigure();
                           var brush = new SolidColorBrush(e.TeamColorEnabled ? Color.FromRgb(player.TeamColor.R, player.TeamColor.G, player.TeamColor.B) : Color.FromRgb(player.Color.R, player.Color.G, player.Color.B));
                           var maxArmySize = 0;
                           var drawingPen = new Pen(brush, 30);
                           for (var iter = 1; iter < player.ArmySize.Count; iter++)
                           {
                              dc.DrawLine(drawingPen, new Point((iter - 1) * 5, player.ArmySize[iter-1]), new Point(iter * 5, player.ArmySize[iter]));
                           }
                        }
                     }
                     
                     image3.Source = new DrawingImage(dGroup);;
               }
         );
      }

      /// <summary>
      /// Called when [unit created].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The e.</param>
      private void OnUnitCreated(object sender, EventArgsUnit e)
      {
         if ((e.Unit.Template.Priority < 5) || !e.Owner.Enemy)
         {
            return;
         }

         var unitname = (!string.IsNullOrEmpty(e.Unit.Template.FrindlyName))
                           ? e.Unit.Template.FrindlyName
                           : e.Unit.ModelName;
         this.OnMessage("New " + unitname);
      }

      /// <summary>
      /// Called when [unit modified].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The e.</param>
      private void OnUnitModified(object sender, EventArgsUnit e)
      {
         if ((e.Unit.Template.Priority < 5) || !e.Owner.Enemy)
         {
            return;
         }

         var unitname = (!string.IsNullOrEmpty(e.Unit.Template.FrindlyName))
                           ? e.Unit.Template.FrindlyName
                           : e.Unit.ModelName;
         this.OnMessage("Mod " + unitname);
      }

      /// <summary>
      /// Called when [unit destroyed].
      /// </summary>
      /// <param name="sender">The sender.</param>
      /// <param name="e">The e.</param>
      private void OnUnitDestroyed(object sender, EventArgsUnit e)
      {
         if ((e.Unit.Template.Priority < 5) || !e.Owner.Enemy)
         {
            return;
         }

         var unitname = (!string.IsNullOrEmpty(e.Unit.Template.FrindlyName))
                           ? e.Unit.Template.FrindlyName
                           : e.Unit.ModelName;
         //this.OnMessage("Unit " + unitname + " destroyed.");
      }

      #endregion
   }
}